// Copyright (c) 2025, 大连理工大学 (Dalian University of Technology)
//
// Licensed under the Mulan PSL v2.
// You can use this file according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of the License at
//
//     http://license.coscl.org.cn/MulanPSL2
//
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. SEE THE MULAN PSL v2
// FOR MORE DETAILS.

#include "DBManager/Service/Result/ResultDomainsService.h"

#include "Utility/Logging/SGLogger.h"

#include "DataStructure/Common/Validation.h"
#include "DataStructure/Input/Solver/Subcase.h"

#include "DBManager/Common/ServiceMacro.h"
#include "DBManager/IService/Input/Subcase/ISubcaseService.h"

using namespace SG::DBManager;
using namespace SG::DataStructure::FEM;
using namespace SG::DataStructure::Post;
using namespace SG::DataStructure::Common;

// Shared helper for SOLType to AnalysisType conversion
namespace
{
    inline AnalysisType ConvertSOLTypeToAnalysisTypeShared (SOLType solType)
    {
        return SG::DataStructure::Post::ConvertSOLTypeToAnalysisType (solType);
    }
}  // namespace

// 注册服务
SERVICE_REG_WITH_DBM_IMPL (ResultDomainsService, IResultDomainsRepository)

ResultDomainsService::ResultDomainsService (DBServiceFactory* const dbServiceFactory, IResultDomainsRepository& repos)
    : m_repository (repos), m_dbServiceFactory (dbServiceFactory)
{}

Status ResultDomainsService::Add (ResultDomains& entity)
{
    return this->AddMeta (entity);
}

Status ResultDomainsService::MAdd (std::vector<DataType>& entity)
{
    for (auto&& i : entity)
    {
        if (AddMeta (i) != Status::STATUS_Success)
        {
            SGError << "Failed to add ResultDomains entity with id: " << i.m_id << std::endl;
            return Status::STATUS_Failure;
        }
    }
    return Status::STATUS_Success;
}

Status ResultDomainsService::FindById (Id id, ResultDomains& domain)
{
    return m_repository.FindById (id, domain);
}

std::vector<Id> ResultDomainsService::GetAllId ()
{
    return m_repository.GetAllId ();
}

Status ResultDomainsService::GetDomainId (const SG::DBManager::Post::DomainRequest& request, _OUT Id& domainID)
{
    ResultDomains domain;
    if (Find (request, domain) == Status::STATUS_Failure)
    {
        domainID = AddFromRequest (request);
        if (domainID == 0)
        {
            SGError << "Failed to add ResultDomains from request: " << request.subcaseId << std::endl;
            return Status::STATUS_Failure;
        }
        // 如果添加成功，则返回新添加的domainID
        return Status::STATUS_Success;
    }

    domainID = domain.m_id;
    return Status::STATUS_Success;
}

Status ResultDomainsService::Find (const SG::DBManager::Post::DomainRequest& request, _OUT ResultDomains& domain)
{
    // 通过subcaseid获取分析类型
    const SOLType analysisType = request.analysisType != SOLType::SOL_UNKNOWN
                                     ? request.analysisType
                                     : m_dbServiceFactory->get<ISubcaseService> ()->GetSOLType (request.subcaseId);

    const std::vector<ResultDomains> allData = m_repository.GetAllData ();

    for (const auto& data : allData)
    {
        // Convert SOLType to AnalysisType for comparison with data.m_Analysis
        const auto analysisTypeForComparison = ConvertSOLTypeToAnalysisTypeShared (analysisType);
        if (analysisTypeForComparison != data.m_Analysis)
            continue;

        if (request.subcaseId != -1 && request.subcaseId != data.m_Subcase)
            continue;

        if (analysisType == SOLType::SOL_SEDTRAN || analysisType == SOLType::SOL_SEMTRAN || analysisType == SOLType::SOL_SEDFREQ
            || analysisType == SOLType::SOL_SEMFREQ || analysisType == SOLType::SOL_SEMCEIG)
            if (!isNear (request.GetTimeModeStepReal (), data.m_TimeFrequencyEigr))
                continue;

        if (analysisType == SOLType::SOL_SEMCEIG && !isNear (request.eigi, data.m_Eigi))
            continue;

        if (analysisType == SOLType::SOL_SEMODES || analysisType == SOLType::SOL_SEBUCKL || analysisType == SOLType::SOL_SEDCEIG
            || analysisType == SOLType::SOL_UNKNOWN)
            if (request.GetTimeModeStepI64 () != data.m_Mode)
                continue;

        if (request.random != SG::DBManager::Post::DomainRequest::RandomResultType::UNKNOWN && static_cast<I64> (request.random) != data.m_Random)
            continue;

        // if (analysisType != SOLType::SOL_SEMODES && analysisType != SOLType::SOL_SEDTRAN)
        //     throw std::runtime_error ("Analysis type not supported for this request. Only Modes and DirectTransient are supported.");

        domain = data;
        return Status::STATUS_Success;
    }
    return Status::STATUS_Failure;
}

const std::vector<ResultDomains> ResultDomainsService::GetAllData ()
{
    return m_repository.GetAllData ();
}

Id ResultDomainsService::AddFromRequest (const SG::DBManager::Post::DomainRequest& request)
{
    // 通过subcaseid获取分析类型
    const SOLType analysisType = request.analysisType != SOLType::SOL_UNKNOWN
                                     ? request.analysisType
                                     : m_dbServiceFactory->get<ISubcaseService> ()->GetSOLType (request.subcaseId);

    ResultDomains newDomain;
    // Convert SOLType to AnalysisType for storage in ResultDomains
    newDomain.m_Analysis =
        analysisType != SOLType::SOL_UNKNOWN ? ConvertSOLTypeToAnalysisTypeShared (analysisType) : AnalysisType::ANALYSISTYPE_Unknown;

    newDomain.m_Subcase = request.subcaseId != -1 ? request.subcaseId : 0;

    if (analysisType == SOLType::SOL_SEMODES || analysisType == SOLType::SOL_SEDCEIG || analysisType == SOLType::SOL_SEBUCKL
        || analysisType == SOLType::SOL_UNKNOWN)
    {
        if (request.GetTimeModeStepI64 () == -1)
        {
            SGError << "when analysis type is modes or null ,must give mode." << std::endl;
            return 0;
        }
        newDomain.m_Mode = request.GetTimeModeStepI64 () != -1 ? request.GetTimeModeStepI64 () : 0;
    }

    // newDomain.m_Step              = request.step != -1 ? request.step : 0;

    if (analysisType == SOLType::SOL_SEDTRAN || analysisType == SOLType::SOL_SEMTRAN || analysisType == SOLType::SOL_SEDFREQ
        || analysisType == SOLType::SOL_SEMFREQ)
    {
        if (request.GetTimeModeStepReal () == -1)
        {
            SGError << "when analysis type is DirectTransient or Frequency,must give time." << std::endl;
            return 0;
        }
        newDomain.m_TimeFrequencyEigr = request.GetTimeModeStepReal () != -1 ? request.GetTimeModeStepReal () : 0;
    }

    if (analysisType == SOLType::SOL_SEMCEIG)
    {
        newDomain.m_Eigi = request.eigi;
    }

    newDomain.m_Random = static_cast<I64> (request.random);

    if (AddMeta (newDomain) == Status::STATUS_Success)
    {
        return newDomain.m_id;
    }
    return 0;
}

Status ResultDomainsService::AddMeta (DataType& entity)
{
    auto dataCount = m_repository.Size ();
    if (dataCount == 0)
    {
        if (entity.m_id == 0)
            entity.m_id++;
        m_repository.Add (entity);
        return Status::STATUS_Success;
    }

    m_repository.UpdataMaxDomainId ();
    auto maxId = m_repository.GetMaxId ();

    if (entity.m_id == 0)
    {
        entity.m_id = maxId + 1;
        m_repository.Add (entity);
        return Status::STATUS_Success;
    }

    if (entity.m_id > maxId)
    {
        m_repository.Add (entity);
        return Status::STATUS_Success;
    }

    return Status::STATUS_Failure;
}
